﻿using FlyingHat.Common.Global;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;

namespace FlyingHat.Extensions.ServiceExtensions
{
    public static class AuthorizationService
    {
        public static void AddAuthorizationService(this IServiceCollection services)
        {
            // Cookie的策略配置
            services.Configure<CookiePolicyOptions>(i =>
            {
                // 检查是否应对此请求评估同意策略
                i.CheckConsentNeeded = context => false;
                i.Secure = CookieSecurePolicy.SameAsRequest;
                i.MinimumSameSitePolicy = SameSiteMode.Unspecified;
                i.OnAppendCookie = context => CheckSameSite(context.Context, context.CookieOptions);
                i.OnDeleteCookie = context => CheckSameSite(context.Context, context.CookieOptions);
            });

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, i =>
                 {
                     // 配置登录url
                     i.LoginPath = new PathString(GlobalConst.LoginPath);
                     // 配置登出url
                     i.LogoutPath = new PathString(GlobalConst.LogoutPath);
                     // 配置登录url
                     i.AccessDeniedPath = new PathString(GlobalConst.AccessDeniedPath);
                     i.SlidingExpiration = false;
                     i.Cookie.HttpOnly = true;
                     i.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
                     // cookie的过期时间会12小时
                     i.ExpireTimeSpan = new TimeSpan(12, 0, 0);
                 });

            // Form配置
            services.Configure<FormOptions>(i =>
            {
                // 设置允许的表单条目数限制。默认1024
                //i.ValueCountLimit = 5000;
                // 设置对单个表单值的长度的限制。默认4MB
                i.ValueLengthLimit = GlobalConst.MaxLimit_40M;
                // 设置Body主体的长度限制。默认128MB
                i.MultipartBodyLengthLimit = GlobalConst.MaxLimit_500M;//int.MaxValue;
                // 设置Header 长度限制。默认16KB
                i.MultipartHeadersLengthLimit = GlobalConst.MaxLimit_1M;
            });
            // 设置Session
            services.AddSession(i =>
            {
                // 允许从存储中加载会话或将其提交回存储的最大时间。注意，这可能只适用于异步操作
                i.IOTimeout = TimeSpan.FromHours(1);
                // 表示会话在其内容被放弃之前可以闲置多长时间。每次会话访问都会重置超时时间。注意，这只适用于会话的内容，而不是cookie。
                i.IdleTimeout = TimeSpan.FromHours(1);
                // 指示客户端脚本是否可以访问cookie
                i.Cookie.HttpOnly = true;
                // 指示该cookie是否为应用程序正常运行所必需
                i.Cookie.IsEssential = true;
            });
        }
        /// <summary>
        /// 浏览器嗅探
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="options"></param>
        private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
        {
            if (options.SameSite == SameSiteMode.None)
            {
                var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
                if (DisallowsSameSiteNone(userAgent))
                {
                    options.SameSite = SameSiteMode.Unspecified;
                }
            }
        }
        private static bool DisallowsSameSiteNone(string userAgent)
        {
            if (string.IsNullOrWhiteSpace(userAgent))
            {
                return false;
            }
            // 基于iOS的浏览器
            if (userAgent.Contains("CPU iPhone OS 12") || userAgent.Contains("iPad; CPU OS 12"))
            {
                return true;
            }
            // 覆盖基于Mac OS X的浏览器
            if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") && userAgent.Contains("Version/") && userAgent.Contains("Safari"))
            {
                return true;
            }
            // 覆盖Chrome 50-69，因为某些版本被SameSite=None破坏，而此范围内的任何版本都不需要它
            if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
            {
                return true;
            }
            return false;
        }
    }
}
